package com.pig4cloud.pig.admin.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pig.admin.api.entity.InfusionCore;
import com.pig4cloud.pig.admin.api.req.InfusionCoreChangeReq;
import com.pig4cloud.pig.admin.api.resp.*;
import com.pig4cloud.pig.admin.mapper.InfusionCoreMapper;
import com.pig4cloud.pig.admin.service.InfusionCoreService;
import com.pig4cloud.pig.common.core.constant.CommonConstants;
import com.pig4cloud.pig.common.core.exception.ValidateCodeException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;

@Service
public class InfusionCoreServiceImpl
		extends ServiceImpl<InfusionCoreMapper, InfusionCore>
		implements InfusionCoreService {

	@Override
	@Transactional(rollbackFor = Exception.class)
	public InfusionCore add(InfusionCore infusionCore) {
		// 计算时长、总输液量
		calculationDuration(infusionCore);
		if (infusionCore.getCoreId() == null) {
			this.save(infusionCore);
		} else {
			this.updateById(infusionCore);
		}
		return infusionCore;
	}
	private final BigDecimal SIXTY = new BigDecimal(60);
	private final BigDecimal THOUSANDS = new BigDecimal(1000);

	private void calculationDuration(InfusionCore infusionCore) {
		BigDecimal ptxs = NumberUtil.toBigDecimal(infusionCore.getPtxs());	// 皮条系数
		BigDecimal ds = NumberUtil.toBigDecimal(infusionCore.getDs()).multiply(SIXTY);	// 滴速 = 滴速 * 60
		BigDecimal totalInfusion = BigDecimal.ZERO;
		BigDecimal normalTime = BigDecimal.ZERO; // 普通输液时间
		BigDecimal normal = BigDecimal.ZERO; // 普通输液量
		if (StrUtil.isNotBlank(infusionCore.getSyal())) {
			normal = normal.add(NumberUtil.toBigDecimal(infusionCore.getSyal()));
		}
		if (StrUtil.isNotBlank(infusionCore.getSybl())) {
			normal = normal.add(NumberUtil.toBigDecimal(infusionCore.getSybl()));
		}
		if (StrUtil.isNotBlank(infusionCore.getSycl())) {
			normal = normal.add(NumberUtil.toBigDecimal(infusionCore.getSycl()));
		}
		if (StrUtil.isNotBlank(infusionCore.getSydl())) {
			normal = normal.add(NumberUtil.toBigDecimal(infusionCore.getSydl()));
		}
		if (StrUtil.isNotBlank(infusionCore.getSyel())) {
			normal = normal.add(NumberUtil.toBigDecimal(infusionCore.getSyel()));
		}
		if (StrUtil.isNotBlank(infusionCore.getSyfl())) {
			normal = normal.add(NumberUtil.toBigDecimal(infusionCore.getSyfl()));
		}
		normalTime = normal.multiply(ptxs).divide(ds, 2, RoundingMode.HALF_UP);

		BigDecimal specialATime = BigDecimal.ZERO; // 特殊A时长
		BigDecimal specialSYL = BigDecimal.ZERO;
		if (StrUtil.isNotBlank(infusionCore.getTssyal())) {
			BigDecimal tssyal = NumberUtil.toBigDecimal(infusionCore.getTssyal());
			BigDecimal tssyads = NumberUtil.toBigDecimal(infusionCore.getTssyads()).multiply(SIXTY);
			specialSYL = specialSYL.add(tssyal);
			specialATime = tssyal.multiply(ptxs).divide(tssyads, 2, RoundingMode.HALF_UP);
		}
		BigDecimal specialBTime = BigDecimal.ZERO; // 特殊B时长
		if (StrUtil.isNotBlank(infusionCore.getTssybl())) {
			BigDecimal tssybl = NumberUtil.toBigDecimal(infusionCore.getTssybl());
			BigDecimal tssybds = NumberUtil.toBigDecimal(infusionCore.getTssybds()).multiply(SIXTY);
			specialSYL = specialSYL.add(tssybl);
			specialBTime = tssybl.multiply(ptxs).divide(tssybds, 2, RoundingMode.HALF_UP);
		}
		BigDecimal totalTime = normalTime.add(specialATime).add(specialBTime).multiply(SIXTY).multiply(SIXTY);
		DateTime yjkssj = DateUtil.parse(infusionCore.getInfusionDate() + StrUtil.SPACE + infusionCore.getYjkssj());
		DateTime yjjssj = DateUtil.offsetSecond(yjkssj,totalTime.intValue());
		infusionCore.setYjjssj(yjjssj.toTimeStr().substring(0, 5));
		infusionCore.setSyyjsc(DateUtil.formatBetween(totalTime.multiply(THOUSANDS).intValue()));
		// 总输液量
		totalInfusion = normal.add(specialSYL);
		infusionCore.setTotalInfusion(totalInfusion.stripTrailingZeros().toPlainString());
	}

	/**
	 * 校验数据
	 * 1、不能维护之前的时间
	 * 2、是否座位在当前时间段内被使用  【查询当日座位列表，代码中按照时间排序后，进行逻辑判断，sql不能使用】
	 * @param infusionCore
	 */
	private void checkInfusion(InfusionCore infusionCore) {
		String date = infusionCore.getInfusionDate();
		// 获取配置
		String yjkssj = infusionCore.getYjkssj();
		DateTime targetDate = DateUtil.parse(date + StrUtil.SPACE + yjkssj);
		int diff = DateUtil.compare(targetDate, DateUtil.date());
		// 不能维护之前的时间
		if (diff <= 0) {
			throw new ValidateCodeException("不能预约之前时间！");
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean change(InfusionCoreChangeReq infusionCoreChangeReq) {
		String timer = DateUtil.date().toTimeStr().substring(0,5);
		LambdaUpdateWrapper<InfusionCore> wrapper = Wrappers.lambdaUpdate(InfusionCore.class)
				.eq(InfusionCore::getCoreId,infusionCoreChangeReq.getCoreId());
		// 开始输液
		if ("start".equals(infusionCoreChangeReq.getType())) {
			// 判断当前座位是否有人继续补液
			this.checkSeatInfusion(infusionCoreChangeReq.getSeatId());
			// 替换座位
			LambdaUpdateWrapper<InfusionCore> updateSeatWrapper = Wrappers.lambdaUpdate(InfusionCore.class)
					.eq(InfusionCore::getCoreId,infusionCoreChangeReq.getCoreId())
					.set(InfusionCore::getSjkssj,timer)
					.set(InfusionCore::getSeatId,infusionCoreChangeReq.getSeatId());
			this.baseMapper.update(updateSeatWrapper);
			return Boolean.TRUE;
		// 切换座位
		} else if ("change".equals(infusionCoreChangeReq.getType())) {
			this.checkSeatInfusion(infusionCoreChangeReq.getSeatId());
			// 替换座位
			LambdaUpdateWrapper<InfusionCore> updateSeatWrapper = Wrappers.lambdaUpdate(InfusionCore.class)
					.eq(InfusionCore::getCoreId,infusionCoreChangeReq.getCoreId())
					.set(InfusionCore::getSeatId,infusionCoreChangeReq.getSeatId());
			this.baseMapper.update(updateSeatWrapper);
			return Boolean.TRUE;
		// 取消预约座位
		} else if ("cancel".equals(infusionCoreChangeReq.getType())) {
			LambdaUpdateWrapper<InfusionCore> lambdaUpdateWrapper = Wrappers.lambdaUpdate(InfusionCore.class)
					.eq(InfusionCore::getCoreId,infusionCoreChangeReq.getCoreId())
					.set(InfusionCore::getDelFlag, CommonConstants.STATUS_DEL);
			this.baseMapper.update(lambdaUpdateWrapper);
			return Boolean.TRUE;
		// 结束输液
		} else if ("end".equals(infusionCoreChangeReq.getType()))  {
			wrapper.set(InfusionCore::getSjjssj,timer);
		}
		this.baseMapper.update(wrapper);
		return Boolean.TRUE;
	}

	private void checkSeatInfusion( String seatId) {
		String today = DateUtil.today();
		InfusionCore infusionCore = this.baseMapper.checkSeatInfusion(today,seatId);
		if (infusionCore != null) {
			throw new ValidateCodeException("该座位还未结束使用！");
		}
	}

	@Override
	public List<ToBeInfusedList> getToBeInfused(String infusionDate) {
		List<ToBeInfusedList> resps = this.baseMapper.getToBeInfused(infusionDate);
		return resps;
	}

	@Override
	public List<InfusionSeatList> getSeats(String infusionDate) {
		List<InfusionSeatList> resps = this.baseMapper.getSeats(infusionDate);
		resps.forEach(item -> {
			String yjsc = item.getSyyjsc();
			if (StrUtil.isNotBlank(yjsc)) {
				if (!yjsc.contains("小时")) {
					yjsc = "0小时" + yjsc;
				}
				if (!yjsc.contains("分")) {
					yjsc = yjsc + "0分";
				}
				if (!yjsc.contains("秒")) {
					yjsc = yjsc + "0秒" ;
				}
				DateTime dateTime = DateUtil.parse(yjsc, "HH小时mm分ss秒");
				int seconds = DateUtil.timeToSecond(dateTime.toString(DatePattern.NORM_TIME_PATTERN));
				item.setSyyjsc(String.valueOf(seconds * 1000));
			}
		});
		return resps;
	}

	@Override
	public Page<InfusionCoreListResp> pageVo(Page<InfusionCore> page, String infusionDate) {
		Page<InfusionCoreListResp> pageVo = this.baseMapper.pageVo(page,infusionDate);
		return pageVo;
	}

	@Override
	public InfusionCoreStatisticsVO statistics(String infusionDate) {
		List<InfusionCoreStatisticsDTO> statisticsDTO = this.baseMapper.statistics(infusionDate);
		InfusionCoreStatisticsVO statisticsVO = new InfusionCoreStatisticsVO(statisticsDTO);
		return statisticsVO;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean coreCancel(String coreId) {
		this.baseMapper.deleteById(coreId);
		return Boolean.TRUE;
	}

	@Override
	public Integer checkSeatNumber(InfusionCore infusionCore) {
		// 校验座位是否已超长
		checkInfusion(infusionCore);
		// 判断是否需要提醒
		String date = infusionCore.getInfusionDate();
		BigDecimal number = BigDecimal.ZERO;
		List<InfusionCore> infusionCoreList = this.baseMapper.getCoreListByDate(date);
		for (InfusionCore core : infusionCoreList) {
			// 已经结束不计算在内
			if (StrUtil.isNotBlank(core.getSjjssj())) {
			// 开始的人员进行计算,开始时间 + 输液时长 计算结束时间
			} else if (StrUtil.isNotBlank(core.getSjkssj())) {
				number = number.add(BigDecimal.ONE);
			// 还未开始的判断时间是否在范围内
			} else {
				String yjkssj = core.getYjkssj();
				String yjjssj = core.getYjjssj();
				DateTime begin = DateUtil.parse(yjkssj);
				DateTime end = DateUtil.parse(yjjssj);
				DateTime newStart = DateUtil.parse(infusionCore.getYjkssj());
				Boolean bool = DateUtil.isIn(newStart,begin,end);
				if (bool) {
					number = number.add(BigDecimal.ONE);
				}
			}
		}
		return number.intValue();
	}

}

